package runesim.node.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import runesim.node.model.Entity;

/**
 * This class is a collection which is backed by 3 seperate Lists. These Lists
 * control the state of this collection. To update this collections current
 * state, you need to explicity call the update method. The purpose of this
 * collection is to seperate new values added to this collection untill the
 * update method has been called. Removal of entities will NOT take effect until
 * the update method is called. This is so we can see what is being removed (and
 * in cases this is required by the server) to handle them specially.
 */

public class StatefulEntityCollection<T extends Entity> {
	
	private Collection<T> newEntities = new HashSet<T>();
	private Collection<T> knownEntities;
	private Collection<T> entitiesToRemove = new HashSet<T>();
	
	@SuppressWarnings("unchecked")
	public StatefulEntityCollection(boolean retainOrder) {
		// knownEntities = retainOrder ? new ArrayList<T>() : new HashSet<T>();
		knownEntities = new LinkedHashSet();
	}
	
	public StatefulEntityCollection() {
		this(true);
	}
	
	public int size() {
		return knownEntities.size();
	}
	
	// We need to keep these in the order they logged in, currently it doesn't
	// seem to?
	
	public void add(T entity) {
		newEntities.add(entity);
	}
	
	public void add(Collection<T> entities) {
		newEntities.addAll(entities);
	}
	
	public boolean contains(T entity) {
		return newEntities.contains(entity) || knownEntities.contains(entity);
	}
	
	public boolean isKnown(T entity) {
		return knownEntities.contains(entity) && !entitiesToRemove.contains(entity);
	}
	
	public void remove(T entity) {
		entitiesToRemove.add(entity);
	}
	
	public boolean isRemoving(T entity) {
		return entitiesToRemove.contains(entity);
	}
	
	public boolean isAdding(T entity) {
		return newEntities.contains(entity);
	}
	
	public void update() {
		knownEntities.removeAll(entitiesToRemove);
		knownEntities.addAll(newEntities);
		newEntities.clear();
		entitiesToRemove.clear();
	}
	
	public String toString(Collection<T> l) {
		StringBuilder out = new StringBuilder();
		Iterator<T> it = l.iterator();
		while(it.hasNext()) {
			out.append(((Entity) (it.next())).getIndex());
			if(it.hasNext())
				out.append(",");
		}
		return out.toString();
	}
	
	public boolean changed() {
		return !entitiesToRemove.isEmpty() || !newEntities.isEmpty();
	}
	
	public Collection<T> getRemovingEntities() {
		return entitiesToRemove;
	}
	
	public Collection<T> getNewEntities() {
		return newEntities;
	}
	
	public Collection<T> getKnownEntities() {
		return knownEntities;
	}
	
	public Collection<T> getAllEntities() {
		List<T> temp = new ArrayList<T>();
		temp.addAll(newEntities);
		temp.addAll(knownEntities);
		return temp;
	}
	
}
